free_xenheap_page(hsa);
}
-/* Set up intercepts to exit the guest into the hypervisor when we want it. */
-static int construct_vmcb_controls(struct arch_svm_struct *arch_svm)
+static int construct_vmcb(struct vcpu *v)
{
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
struct vmcb_struct *vmcb = arch_svm->vmcb;
- u32 *iopm, *msrpm;
+ segment_attributes_t attrib;
+ unsigned long dr7;
- /* mask off all general 1 intercepts except those listed here */
+ /* SVM intercepts. */
vmcb->general1_intercepts =
GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI |
GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT |
GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG |
GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT |
GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT;
-
- /* turn on the general 2 intercepts */
vmcb->general2_intercepts =
GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL |
GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE |
GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI |
GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
- /* read or write all debug registers 0 - 15 */
+ /* Intercept all debug-register writes. */
vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
- /* RD/WR all control registers 0 - 15, but not read CR2 */
+ /* Intercept all control-register accesses, except to CR2. */
vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
- /* The following is for I/O and MSR permision map */
- iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
- if ( iopm != NULL )
+ /* I/O and MSR permission bitmaps. */
+ arch_svm->iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
+ arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
+ if ( (arch_svm->iopm == NULL) || (arch_svm->msrpm == NULL) )
{
- memset(iopm, 0xff, IOPM_SIZE);
- clear_bit(PC_DEBUG_PORT, iopm);
+ free_xenheap_pages(arch_svm->iopm, get_order_from_bytes(IOPM_SIZE));
+ free_xenheap_pages(arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
+ return -ENOMEM;
}
- msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
- if ( msrpm != NULL )
- memset(msrpm, 0xff, MSRPM_SIZE);
-
- arch_svm->iopm = iopm;
- arch_svm->msrpm = msrpm;
-
- if ( !iopm || !msrpm )
- return 1;
-
- vmcb->iopm_base_pa = (u64) virt_to_maddr(iopm);
- vmcb->msrpm_base_pa = (u64) virt_to_maddr(msrpm);
-
- return 0;
-}
-
-
-/*
- * Initially set the same environement as host.
- */
-static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm,
- struct cpu_user_regs *regs )
-{
- int error = 0;
- unsigned long crn;
- segment_attributes_t attrib;
- unsigned long dr7;
- unsigned long shadow_cr;
- struct vmcb_struct *vmcb = arch_svm->vmcb;
+ memset(arch_svm->iopm, 0xff, IOPM_SIZE);
+ clear_bit(PC_DEBUG_PORT, arch_svm->iopm);
+ memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
+ vmcb->iopm_base_pa = (u64)virt_to_maddr(arch_svm->iopm);
+ vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
- /* Allows IRQs to be shares */
+ /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
vmcb->vintr.fields.intr_masking = 1;
- /* Set up event injection entry in VMCB. Just clear it. */
+ /* Initialise event injection to no-op. */
vmcb->eventinj.bytes = 0;
- /* TSC */
+ /* TSC. */
vmcb->tsc_offset = 0;
- vmcb->cs.sel = regs->cs;
- vmcb->es.sel = regs->es;
- vmcb->ss.sel = regs->ss;
- vmcb->ds.sel = regs->ds;
- vmcb->fs.sel = regs->fs;
- vmcb->gs.sel = regs->gs;
-
- /* Guest segment Limits. 64K for real mode*/
+ /* Guest segment limits. */
vmcb->cs.limit = GUEST_SEGMENT_LIMIT;
vmcb->es.limit = GUEST_SEGMENT_LIMIT;
vmcb->ss.limit = GUEST_SEGMENT_LIMIT;
vmcb->fs.limit = GUEST_SEGMENT_LIMIT;
vmcb->gs.limit = GUEST_SEGMENT_LIMIT;
- /* Base address for segments */
+ /* Guest segment bases. */
vmcb->cs.base = 0;
vmcb->es.base = 0;
vmcb->ss.base = 0;
vmcb->fs.base = 0;
vmcb->gs.base = 0;
- /* Guest Interrupt descriptor table */
- vmcb->idtr.base = 0;
- vmcb->idtr.limit = 0;
-
- /* Set up segment attributes */
+ /* Guest segment AR bytes. */
attrib.bytes = 0;
attrib.fields.type = 0x3; /* type = 3 */
- attrib.fields.s = 1; /* code or data, i.e. not system */
- attrib.fields.dpl = 0; /* DPL = 0 */
- attrib.fields.p = 1; /* segment present */
- attrib.fields.db = 1; /* 32-bit */
- attrib.fields.g = 1; /* 4K pages in limit */
-
- /* Data selectors */
+ attrib.fields.s = 1; /* code or data, i.e. not system */
+ attrib.fields.dpl = 0; /* DPL = 0 */
+ attrib.fields.p = 1; /* segment present */
+ attrib.fields.db = 1; /* 32-bit */
+ attrib.fields.g = 1; /* 4K pages in limit */
vmcb->es.attributes = attrib;
vmcb->ss.attributes = attrib;
vmcb->ds.attributes = attrib;
vmcb->fs.attributes = attrib;
vmcb->gs.attributes = attrib;
-
- /* Code selector */
- attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
+ attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
vmcb->cs.attributes = attrib;
- /* Guest Global descriptor table */
+ /* Guest IDT. */
+ vmcb->idtr.base = 0;
+ vmcb->idtr.limit = 0;
+
+ /* Guest GDT. */
vmcb->gdtr.base = 0;
vmcb->gdtr.limit = 0;
- /* Guest Local Descriptor Table */
- attrib.fields.s = 0; /* not code or data segement */
+ /* Guest LDT. */
+ attrib.fields.s = 0; /* not code or data segement */
attrib.fields.type = 0x2; /* LDT */
- attrib.fields.db = 0; /* 16-bit */
- attrib.fields.g = 0;
+ attrib.fields.db = 0; /* 16-bit */
+ attrib.fields.g = 0;
vmcb->ldtr.attributes = attrib;
+ /* Guest TSS. */
attrib.fields.type = 0xb; /* 32-bit TSS (busy) */
vmcb->tr.attributes = attrib;
vmcb->tr.base = 0;
vmcb->tr.limit = 0xff;
- __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) :);
- vmcb->cr0 = crn;
+ /* Guest CR0. */
+ vmcb->cr0 = read_cr0();
+ arch_svm->cpu_shadow_cr0 = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS);
- /* Initally PG, PE are not set*/
- shadow_cr = vmcb->cr0;
- shadow_cr &= ~X86_CR0_PG;
- arch_svm->cpu_shadow_cr0 = shadow_cr;
+ /* Guest CR4. */
+ arch_svm->cpu_shadow_cr4 =
+ read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
+ vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK;
- /* CR3 is set in svm_final_setup_guest */
+ /* Guest DR7. */
+ __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
+ vmcb->dr7 = dr7;
- __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) :);
- crn &= ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
- arch_svm->cpu_shadow_cr4 = crn;
- vmcb->cr4 = crn | SVM_CR4_HOST_MASK;
+ arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
- vmcb->rsp = 0;
- vmcb->rip = regs->eip;
+ return 0;
+}
- vmcb->rflags = regs->eflags | 2UL; /* inc. reserved bit */
+int svm_create_vmcb(struct vcpu *v)
+{
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
+ int rc;
- __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
- vmcb->dr7 = dr7;
+ if ( (arch_svm->vmcb = alloc_vmcb()) == NULL )
+ {
+ printk("Failed to create a new VMCB\n");
+ return -ENOMEM;
+ }
- return error;
+ if ( (rc = construct_vmcb(v)) != 0 )
+ {
+ free_vmcb(arch_svm->vmcb);
+ arch_svm->vmcb = NULL;
+ return rc;
+ }
+
+ arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb);
+
+ return 0;
}
-void destroy_vmcb(struct arch_svm_struct *arch_svm)
+void svm_destroy_vmcb(struct vcpu *v)
{
+ struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
+
if ( arch_svm->vmcb != NULL )
{
asidpool_retire(arch_svm->vmcb, arch_svm->asid_core);
arch_svm->vmcb = NULL;
}
-int construct_vmcb(struct arch_svm_struct *arch_svm,
- struct cpu_user_regs *regs)
-{
- if ( construct_vmcb_controls(arch_svm) != 0 )
- {
- printk("construct_vmcb: construct_vmcb_controls failed\n");
- return -EINVAL;
- }
-
- if ( construct_init_vmcb_guest(arch_svm, regs) != 0 )
- {
- printk("construct_vmcb: construct_vmcb_guest failed\n");
- return -EINVAL;
- }
-
- arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
- if ( regs->eflags & EF_TF )
- arch_svm->vmcb->exception_intercepts |= EXCEPTION_BITMAP_DB;
- else
- arch_svm->vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_DB;
-
- return 0;
-}
-
-
void svm_do_launch(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;